package com.cyper.mvnbook.account.persist;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import java.io.*;
import java.util.List;

/**
 * Created by cyper on 11/21/14.
 */
public class AccountPersistServiceImpl implements AccountPersistService {
    private static final String ELEMENT_ROOT = "account-persist";
    private static final String ELEMENT_ACCOUNTS = "accounts";
    private static final String ELEMENT_ACCOUNT_ID = "id";
    private static final String ELEMENT_ACCOUNT_NAME = "name";
    private static final String ELEMENT_ACCOUNT_EMAIL = "email";
    private static final String ELEMENT_ACCOUNT_PASSWORD = "password";
    private static final String ELEMENT_ACCOUNT_ACTIVATED = "activated";
    private static final String ELEMENT_ACCOUNT = "account";
    private String file;

    private SAXReader reader = new SAXReader();

    private Document readDocument() throws AccountPersistException {
        File dataFile = new File(file);
        if (!dataFile.exists()) {
            dataFile.getParentFile().mkdirs();
            Document doc = DocumentFactory.getInstance().createDocument();
            Element rootEle = doc.addElement(ELEMENT_ROOT);
            rootEle.addElement(ELEMENT_ACCOUNTS);
            writeDocument(doc);
        }

        try {
            return reader.read(new File(file));
        } catch (DocumentException e) {
            throw new AccountPersistException("unable to read xml", e);
        }
    }

    private void writeDocument(Document doc) throws AccountPersistException {
        Writer out = null;
        try {
            out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            XMLWriter writer = new XMLWriter(out, OutputFormat.createPrettyPrint());
            writer.write(doc);

        } catch (Exception e) {
            throw new AccountPersistException("unable to write xml", e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    throw new AccountPersistException("unable to close writer.", e);
                }
            }
        }
    }

    @Override
    public Account createAccount(Account account) throws AccountPersistException {
        Account existed = readAccount(account.getId());
        if (existed == null) {
            Document doc = readDocument();
            Element root = doc.getRootElement();
            Element accounts = (Element) root.elementIterator().next();
            Element acc = accounts.addElement(ELEMENT_ACCOUNT);
            Element id = acc.addElement(ELEMENT_ACCOUNT_ID);
            id.setText(account.getId());

            Element name = acc.addElement(ELEMENT_ACCOUNT_NAME);
            name.setText(account.getName());

            Element email = acc.addElement(ELEMENT_ACCOUNT_EMAIL);
            email.setText(account.getEmail());


            Element pwd = acc.addElement(ELEMENT_ACCOUNT_PASSWORD);
            pwd.setText(account.getPassword());

            Element activiated = acc.addElement(ELEMENT_ACCOUNT_ACTIVATED);
            activiated.setText(String.valueOf(account.isActivated()));

            writeDocument(doc);

            return account;
        }

        return null;
    }

    @Override
    public Account readAccount(String id) throws AccountPersistException {
        Document doc = readDocument();
        Element accountsEle = doc.getRootElement().element(ELEMENT_ACCOUNTS);
        for (Element accountEle : (List<Element>) accountsEle.elements()) {
            if (accountEle.elementText(ELEMENT_ACCOUNT_ID).equals(id)) {
                return buildAccount(accountEle);
            }
        }
        return null;
    }

    private Account buildAccount(Element accountEle) {
        Account account = new Account();
        account.setId(accountEle.elementText(ELEMENT_ACCOUNT_ID));
        account.setName(accountEle.elementText(ELEMENT_ACCOUNT_NAME));
        account.setEmail(accountEle.elementText(ELEMENT_ACCOUNT_EMAIL));
        account.setPassword(accountEle.elementText(ELEMENT_ACCOUNT_PASSWORD));
        account.setActivated("true".equals(accountEle.elementText(ELEMENT_ACCOUNT_ACTIVATED)));
        return account;
    }

    @Override
    public Account updateAccount(Account account) throws AccountPersistException {
        return null;
    }

    @Override
    public void deleteAccount(String id) throws AccountPersistException {

    }

    public void setFile(String file) {
        this.file = file;
    }
}
